home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 048 (1988-02-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 048 (1988-02-15)(Ossowski, Stefan)(DE)(PD).adf / Mandel / source / gotmenu.c < prev    next >
C/C++ Source or Header  |  1988-01-23  |  23KB  |  811 lines

  1. #define DEBUG
  2.  
  3. /* :ts=4
  4.  * M A N D E L B R O T   C O N S T R U C T I O N   S E T
  5.  * 
  6.  * MenuPick and some related things
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #ifndef EXEC_SEMAPHORES_H
  11. #include <exec/semaphores.h>
  12. #endif
  13. #include <intuition/intuition.h>
  14. #ifdef DEBUG
  15. #    include <stdio.h>
  16. #    undef STATIC
  17. #    define STATIC    /* EMPTY */
  18. #endif
  19. #include "mandel.h"
  20.  
  21. STATIC TEXT FileName[FNAME_SIZE+1] = "Mandel.pic";
  22. STATIC TEXT DirName[DNAME_SIZE+2]  = "df0:";
  23. STATIC UBYTE Buffer[5][20];
  24.  
  25. /* Forward declarations of static procedures */
  26. void PrjNew();
  27.  
  28. void GotMenu(Code)
  29. USHORT Code;
  30. {
  31.     static void (*MenuFunc[])()= { 
  32.         CprMenu, PrjMenu, OptMenu, FunMenu     };
  33.     while (Code != MENUNULL) {
  34.         (*MenuFunc[MENUNUM(Code)]) (Code);
  35.         Code = ItemAddress(MandelMenu, (long) Code) -> NextSelect;
  36.         /* This tends to make endless loops possible ... */
  37.     }
  38. }
  39.  
  40. void CprMenu(Code)
  41. USHORT Code;
  42. {
  43.     ULONG OldIDCMP = MainWindow->IDCMPFlags;
  44.  
  45.     static struct IntuiText Body[] =
  46.     {  
  47.         {   MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  48.             10, 15, NULL, (UBYTE *)"Mandelbrot Construction Set", &Body[1] },
  49.         {   MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  50.             10, 30, NULL, (UBYTE *)"By KosmoSoft Productions", &Body[2] },
  51.         {   MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  52.             10, 40, NULL, (UBYTE *)"15 September 1987 V1.0", &Body[3] },
  53.         {   MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  54.             10, 55, NULL, (UBYTE *)"Ohh, please Copy-Me!", NULL }
  55.     },
  56.     ExitText =
  57.     {   MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE,
  58.         AUTOLEFTEDGE, AUTOTOPEDGE, NULL, (UBYTE *)" OK ", NULL };
  59.  
  60.     ModifyIDCMP(MainWindow, OldIDCMP &~ (MENUVERIFY | SIZEVERIFY | REQVERIFY));
  61.     AutoRequest(MainWindow, &Body[0], NULL, &ExitText, NULL, NULL, 258L, 100L);
  62.     ModifyIDCMP(MainWindow, OldIDCMP);
  63. }
  64.  
  65. STATIC void PrjMenu(Code)
  66. USHORT Code;
  67. {
  68.     int SubNum = SUBNUM(Code);
  69.     int ItemNum = ITEMNUM(Code);
  70.  
  71.     struct Mand MandChunk;
  72.     struct BitMap *bitmap;
  73.     struct ILBM_info *ilbminfo;
  74.     unsigned char ea_colormap[3*MAXCOL];
  75.     char Name[DNAME_SIZE + FNAME_SIZE + 3];
  76.  
  77.     switch (ItemNum) {
  78.     case PRJNEW: PrjNew(SubNum); break;
  79.     case PRJOPN:
  80.         if ( get_fname(MainWindow, "Select a filename to LOAD",
  81.                 FileName, DirName) == NULL ) break;
  82.         strcpy(Name, DirName);
  83.         if (Name[strlen(Name) - 1] != ':') strcat(Name, "/");
  84.         strcat(Name, FileName);
  85.         StopDrawing();
  86.         MandChunk.MandID = 0;
  87.         if (ilbminfo =  read_iff(Name, 
  88.             (short)FALSE, sizeof(MandChunk), &MandChunk)) {
  89.             put_ea_cmap(&ilbminfo->cmap, NumColors, MandelScreen);
  90.             InterpretMAND(&MandChunk);
  91.         }
  92.         Saved = TRUE;
  93.         break;
  94.     case PRJSVE:    /* Save */
  95.         if (NameValid) skipto prjsve;
  96.         /* Fall Through */
  97.     case PRJSVA:    /* Save As */
  98.         if ( get_fname(MainWindow, "Select a filename to SAVE",
  99.                 FileName, DirName) == NULL ) break;
  100. prjsve:
  101.         strcpy(Name, DirName);
  102.         if (Name[strlen(Name) - 1] != ':') strcat(Name, "/");
  103.         strcat(Name, FileName);
  104.         get_ea_cmap(ea_colormap, NumColors, MandelScreen);
  105.         MakeMAND(&MandChunk);
  106.         bitmap = MainWindow->RPort->BitMap;
  107. /*** Warning: This MoveWindow will not happen immediately!!!    ***/
  108. /*** For some reason, this will deadlock Intuition, if I        ***/
  109. /*** uncomment both MoveWindow and DoBorderless. It seems to    ***/
  110. /*** collide with the closing filename requester window...      ***/
  111. /*** Maybe because the locking of the layers interfere buggyly? ***/
  112. /*** Anyhow, if I LockLayers(), then the GZZ border doesn't     ***/
  113. /*** get updated until I UnlockLayers(), and the mouse          ***/
  114. /*** pointer is frozen! But we have to suspend the drawing      ***/
  115. /*** task somehow, to prevent creating a corrupt IFF file.      ***/
  116. /*** Who said `Very near to betting that it can't be            ***/
  117. /*** deadlocked' ?? [allchanges file: intuition 290]            ***/
  118.         /*     MoveWindow(MainWindow, (long)-MainWindow->LeftEdge,
  119.             (long)-MainWindow->TopEdge); */
  120.         /* DoBorderless(MainWindow); */
  121.         SuspendDrawing();
  122.         NameValid = Saved = write_iff(Name, ea_colormap, bitmap,
  123.                 (short) 0, (short) 0, (short) bitmap->BytesPerRow * 8,
  124.                 (short) TRUE, sizeof(MandChunk), &MandChunk);
  125.         ResumeDrawing();
  126.         break;
  127.     case PRJQUI:
  128.         if (StillDrawing)
  129.             StopDrawing();
  130.         else
  131.             finished = TRUE;
  132.     }
  133. }
  134.  
  135. STATIC void OptMenu(Code)
  136. USHORT Code;
  137. {
  138.     int SubNum = SUBNUM(Code);
  139.     int ItemNum = ITEMNUM(Code);
  140.  
  141.     switch (ItemNum) {
  142.     case OPTCOL:
  143.         switch (SubNum) {
  144.         case OCSEL:
  145.             SelectMenu(MENU(OPTMENU, OPTCOL, OCSEL), (bool)FALSE);
  146.             UnImpl(); break;
  147.         case OCMOD:
  148.             PenTableMode = MODULO; break;
  149.         case OCRAN:
  150.             PenTableMode = RANGES; break;
  151.         case OCPAL:
  152.             Palette(MainWindow);
  153.         } /* End Switch SUBNUM */
  154.         InitPenTable();
  155.         break;
  156.     case OPTRES:
  157.         switch (SubNum) {
  158.         case ORNRM: PixelStep = 1; break;
  159.         case OR12:  PixelStep = 2; break;
  160.         case OR13:  PixelStep = 3; break;
  161.         case OR14:  PixelStep = 4; break;
  162.         case ORFIL:
  163.             DrawPicture((bool)TRUE); break;    /* Fill in */
  164.         case ORHI:
  165.         case ORILC: 
  166.             if (!Sure()) break;
  167.             {
  168.                 USHORT newmode = MandelNScreen.ViewModes & ~(HIRES | LACE);
  169.                 bool WasBorderless;
  170.  
  171.                 if (ItemAddress(MandelMenu, MENU(OPTMENU, OPTRES, ORHI))
  172.                     -> Flags & CHECKED)
  173.                         newmode |= HIRES;
  174.                 if (ItemAddress(MandelMenu, MENU(OPTMENU, OPTRES, ORILC))
  175.                     -> Flags & CHECKED)
  176.                         newmode |= LACE;
  177.                 if (newmode != MandelNScreen.ViewModes) {
  178.                     WasBorderless = CleanupDisplay((bool) TRUE);
  179.                     MandelNScreen.ViewModes = newmode;
  180.                     if (InitDisplay(WasBorderless)) { /* Trouble */
  181.                         MandelNScreen.ViewModes &= ~(HIRES | LACE);
  182.                         if (InitDisplay((bool) FALSE))
  183.                             MyExit("Can't re-init display - Maybe low on memory");
  184.                         SelectMenu(MENU(OPTMENU, OPTRES, ORHI), (bool)FALSE);
  185.                         SelectMenu(MENU(OPTMENU, OPTRES, ORILC), (bool)FALSE);
  186.                         SelectMenu(MENU(OPTMENU, OPTRES, ORBCK), (bool)FALSE);
  187.                     }
  188.                 }
  189.             }
  190.             break;
  191.         case ORBCK: 
  192.             if (ItemAddress(MandelMenu, MENU(OPTMENU,OPTRES,ORBCK))->Flags & CHECKED)
  193.                 DoBorderless(MainWindow, &borderinfo);
  194.             else
  195.                 UndoBorderless(MainWindow, &borderinfo);
  196.         } /* End Switch SUBNUM */
  197.         break;
  198.     case OPTPAR: Parameters(); break;
  199.     } /* End Switch ITEMNUM */
  200. }
  201.  
  202. void FunMenu(Code)
  203. USHORT Code;
  204. {
  205.     switch (ITEMNUM(Code)) {
  206.     case FUN1:
  207.         WritePixelDepth = ZQuadMinC; break;
  208.     case FUN2:
  209.         WritePixelDepth = ZC1MinZ; break;
  210.     case FUN3:
  211.         WritePixelDepth = Z3PlusZCMin1MinC; break;
  212.     }
  213. }
  214.  
  215. void UnImpl()
  216. {
  217.     static char alert[] = "\
  218. \0\144\25Mandelbrot Construction Set -- By KosmoSoft Productions\0a\
  219. \0\170\40Sorry, this function has not been implemented yet!\0";
  220.     DisplayAlert(RECOVERY_ALERT, alert, 50L);
  221. }
  222.  
  223. STATIC USHORT OldMinWidth, OldMinHeight, OldMaxWidth, OldMaxHeight;
  224.  
  225. /* Do not nest calls to DisableSizing: the original values will be lost. */
  226.  
  227. STATIC void DisableSizing()
  228. {
  229.     OldMinWidth = MainWindow->MinWidth;
  230.      OldMaxWidth = MainWindow->MaxWidth;
  231.     OldMinHeight = MainWindow->MinHeight;
  232.     OldMaxHeight = MainWindow->MaxHeight;
  233.     WindowLimits(MainWindow, (long) MainWindow->Width, (long) MainWindow->Height,
  234.                     (long) MainWindow->Width, (long) MainWindow->Height);
  235. }
  236.  
  237. STATIC void EnableSizing()
  238. {
  239.     WindowLimits(MainWindow, (long) OldMinWidth, (long) OldMinHeight,
  240.                     (long) OldMaxWidth, (long) OldMaxHeight);
  241. }
  242.  
  243. /* Complex multiplication using pointers to reduce overhead.   */
  244. /* YOU must make sure there are no (dynamic) aliases around... */
  245.  
  246. STATIC void MulCplx(ReRes, ImRes, ReA, ImA, ReB, ImB)
  247. double *ReRes, *ImRes, *ReA, *ImA, *ReB, *ImB;
  248. {
  249.     *ReRes = *ReA * *ReB - *ImA * *ImB;
  250.     *ImRes = *ImA * *ReB + *ReA * *ImB;
  251. }
  252.  
  253. /* Z^2-C: 4 multiplications per loop */
  254.  
  255. void ZQuadMinC(x, y, ReC, ImC)
  256. long x, y;
  257. double ReC, ImC;
  258. {
  259.     double ReZ = 0.0, ImZ = 0.0;
  260.     double ReQuad, ImQuad;
  261.     int Depth = -1;
  262.  
  263.     while (ImQuad=ImZ*ImZ, ReQuad=ReZ*ReZ, Depth++,
  264.         (ImQuad + ReQuad < 8) && (Depth <= MaxDepth) )
  265.     {
  266.         ImZ = 2 * ImZ * ReZ - ImC;
  267.         ReZ = ReQuad - ImQuad - ReC;
  268.     }
  269.  
  270.     if (Depth > MaxDepth)
  271.         Depth = PenTable[0];
  272.     else 
  273.         Depth = PenTable[Depth];
  274.  
  275.     SetAPen(MainWindow->RPort, (long) Depth);
  276.     WritePixel(MainWindow->RPort, x, y);
  277. }
  278.  
  279. /* Z*C*(1-Z): 10 multiplications per loop */
  280.  
  281. void ZC1MinZ(x, y, ReC, ImC)
  282. long x, y;
  283. double ReC, ImC;
  284. {
  285.     static double ReZ, ImZ;
  286.     static double NewReZ, NewImZ;
  287.     static double Re1MinZ, Im1MinZ;
  288.     int Depth = -1;
  289.  
  290.     ReZ = ReC;
  291.     ImZ = ImC;
  292.  
  293.     while (Depth++, (ImZ*ImZ + ReZ*ReZ < 8) && (Depth <= MaxDepth) )
  294.     {
  295.         Re1MinZ = 1 - ReZ;
  296.         Im1MinZ = -ImZ;
  297.         MulCplx(&NewReZ, &NewImZ, &ReZ, &ImZ, &ReC, &ImC);
  298.         MulCplx(&ReZ, &ImZ, &NewReZ, &NewImZ, &Re1MinZ, &Im1MinZ);
  299.     }
  300.  
  301.     if (Depth > MaxDepth)
  302.         Depth = PenTable[0];
  303.     else 
  304.         Depth = PenTable[Depth];
  305.  
  306.     SetAPen(MainWindow->RPort, (long) Depth);
  307.     WritePixel(MainWindow->RPort, x, y);
  308. }
  309.  
  310. /* Z^3+Z*(C-1)-C: 12 multiplications per loop */
  311.  
  312. void Z3PlusZCMin1MinC(x, y, ReC, ImC)
  313. long x, y;
  314. double ReC, ImC;
  315. {
  316.     static double ReZ, ImZ;
  317.     static double ReCMin1;
  318.     static double ReZ2, ImZ2, ReZ3, ImZ3;
  319.     double ReQuad, ImQuad;
  320.     int Depth = -1;
  321.  
  322.     ReZ = ReC;
  323.     ImZ = ImC;
  324.  
  325.     while (ImQuad=ImZ*ImZ, ReQuad=ReZ*ReZ, Depth++,
  326.         (ImQuad + ReQuad < 8) && (Depth <= MaxDepth) )
  327.     {
  328.         /* Calculate z^2 */
  329.         ReZ2 = ReQuad - ImQuad;
  330.         ImZ2 = 2 * ReZ * ImZ;
  331.  
  332.         /* Make z^3 */
  333.         MulCplx(&ReZ3, &ImZ3, &ReZ2, &ImZ2, &ReZ, &ImZ);
  334.  
  335.         /* Calculate z(c-1) while destroying z^2 */
  336.         ReCMin1 = ReC - 1;
  337.         MulCplx(&ReZ2, &ImZ2, &ReZ, &ImZ, &ReCMin1, &ImC);
  338.  
  339.         /* Add everything */
  340.         ReZ = ReZ3 + ReZ2 - ReC;
  341.         ImZ = ImZ3 + ImZ2 - ImC;
  342.     }
  343.  
  344.     if (Depth > MaxDepth)
  345.         Depth = PenTable[0];
  346.     else 
  347.         Depth = PenTable[Depth];
  348.  
  349.     SetAPen(MainWindow->RPort, (long) Depth);
  350.     WritePixel(MainWindow->RPort, x, y);
  351. }
  352.  
  353. /* Some *VERY PRIVATE* variables */
  354.  
  355. STATIC struct Task *DrawTask = NULL;
  356. STATIC struct Task *MandelTask = NULL;
  357. STATIC struct SignalSemaphore DrawSemaphore;
  358.  
  359. /* This is what it is all about! */
  360.  
  361. STATIC bool MyFillIn;    /* Parameter for new task */
  362.  
  363. STATIC void ActuallyDrawPicture()
  364. {
  365.     static double x, y, Leftx, MyXstep, MyYstep;
  366.     static long px, py, Leftpx, minpx, maxpx, minpy, maxpy;
  367.     static int MyPixelStep, XOffset, YOffset;
  368.  
  369.     register void (*Function)();
  370.  
  371.     geta4();        /* Manx small memory model */
  372.  
  373.     ObtainSemaphore(&DrawSemaphore);
  374.  
  375.     StillDrawing = TRUE;
  376.     DisableSizing();
  377.     StopFraming();
  378.     OffMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
  379.         SHIFTSUB(NOSUB) );
  380.     OffMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
  381.         SHIFTSUB(ORFIL) );
  382.  
  383.     if (!MyFillIn && !Sure())    skipto exit;
  384.     if (!MyFillIn)    NameValid = FALSE;
  385.     Saved = FALSE;
  386.     MyPixelStep = PixelStep;
  387.     XOffset = 0;
  388.     YOffset = MyFillIn? 1: 0;
  389.  
  390.     minpx = 0;
  391.     maxpx = MainWindow->GZZWidth - 1;
  392.     minpy = 0;
  393.     maxpy = MainWindow->GZZHeight - 1;
  394.  
  395.     CalcCSteps();
  396.  
  397.     if (!MyFillIn) {    /* Clear the window */
  398.         SetAPen(MainWindow->RPort, (long) PenTable[0]);
  399.         SetDrMd(MainWindow->RPort, (long) JAM1);
  400.         RectFill(MainWindow->RPort, minpx, minpy, maxpx, maxpy);
  401.     }
  402.  
  403.     MyXstep = MyPixelStep * CXStep;
  404.     MyYstep = MyPixelStep * CYStep;
  405.  
  406.     Function = WritePixelDepth;
  407.  
  408.     ReleaseSemaphore(&DrawSemaphore);
  409.  
  410. again:
  411.     Leftpx = minpx + XOffset;    /* Start in the upper left-hand corner */
  412.     py = minpy + YOffset;        /* of the window */
  413.     Leftx = LeftEdge + XOffset * CXStep;
  414.     y = TopEdge - YOffset * CYStep;
  415.  
  416.     for ( ; py <= maxpy; y -= MyYstep, py += MyPixelStep) {
  417.         ObtainSemaphore(&DrawSemaphore);
  418.         SetDrMd(MainWindow->RPort, (long) JAM1);
  419.         for (px=Leftpx, x=Leftx ; px <= maxpx; x += MyXstep, px += MyPixelStep) {
  420.             (*Function)(px, py, x, y);
  421.             /* Check if we are asked to terminate. Don't release s'phore. */
  422.             if (StillDrawing < 0)    skipto exit;
  423.         }
  424.         ReleaseSemaphore(&DrawSemaphore);
  425.     }
  426.  
  427.     if (MyFillIn && (++YOffset < MyPixelStep) ) {
  428.         backto again;         /* Draw pixels below current pixel */
  429.     }
  430.     if (MyFillIn && (++XOffset < MyPixelStep) ) {
  431.         YOffset = 0;        /* and next to them */
  432.         backto again;
  433.     }
  434.  
  435. exit:
  436.     DisplayBeep(MandelScreen);
  437.     ObtainSemaphore(&DrawSemaphore);
  438.     EnableSizing();
  439.     OnMenu(MainWindow, (ULONG) SHIFTMENU(PRJMENU) | SHIFTITEM(PRJNEW) |
  440.         SHIFTSUB(NOSUB) );
  441.     OnMenu(MainWindow, (ULONG) SHIFTMENU(OPTMENU) | SHIFTITEM(OPTRES) |
  442.         SHIFTSUB(ORFIL) );
  443.     DrawTask = NULL;
  444.     if (StillDrawing < 0) {
  445.         /* Release the semaphore now. The main task waits for it. */
  446.         ReleaseSemaphore(&DrawSemaphore);
  447.     }
  448.     StillDrawing = FALSE;    /* We are finished, finally... */
  449.     ReleaseSemaphore(&DrawSemaphore);
  450.     DisplayBeep(MandelScreen);
  451. }
  452.  
  453. void DrawPicture(FillIn)
  454. bool FillIn;
  455. {
  456.     BYTE Priority;
  457.  
  458.     MandelTask = FindTask(NULL);
  459.     Priority = MandelTask->tc_Node.ln_Pri;
  460.     MyFillIn = FillIn;
  461.  
  462.     InitSemaphore(&DrawSemaphore);
  463.  
  464.     DrawTask = CreateTask("Mandelbrot_Drawing.task", (long) Priority,
  465.         ActuallyDrawPicture, 2048L);
  466.  
  467. }
  468.  
  469. /* Interface because I wanted to CreateTask the drawing... */
  470.  
  471. void StopDrawing()
  472. {
  473.     if (StillDrawing) {
  474.         StillDrawing = -1;    /* Indicate termination is wanted. */
  475.  
  476.         /* In worst-case I think we will make the loop at most twice. */
  477.         /* This is only when the drawing task has not obtained it, */
  478.         /* which is only for very little of the time. */
  479.         do {
  480.             ObtainSemaphore(&DrawSemaphore);
  481.             ReleaseSemaphore(&DrawSemaphore);
  482.         } while (StillDrawing < 0);
  483.     }
  484. }
  485.  
  486. /* This is the external interface to the DrawSemaphore. Use it with care. */
  487. /* Always balance calls to SuspendDrawing() with ResumeDrawing() !!! */
  488.  
  489. void SuspendDrawing()
  490. {
  491.     ObtainSemaphore(&DrawSemaphore);
  492. }
  493.  
  494. void ResumeDrawing()
  495. {
  496.     ReleaseSemaphore(&DrawSemaphore);
  497. }
  498.  
  499. STATIC void PrjNew(SubNum)
  500. USHORT SubNum;
  501. {
  502.     struct Window *window;
  503.     int ID;
  504.     static double HShift = 0.0,
  505.         VShift = 0.0;
  506.     double Width = RightEdge - LeftEdge,
  507.         Height = BottomEdge - TopEdge,
  508.         NewLeftEdge = LeftEdge,
  509.         NewTopEdge = TopEdge,
  510.         NewRightEdge = RightEdge,
  511.         NewBottomEdge = BottomEdge;
  512.  
  513.     /* Stuff for the ABSOLUTE requester */
  514.  
  515.     static struct IntuiText RatioText = {
  516.         MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 10, 90, NULL,
  517.         (UBYTE *) "Ratio:                    ", NULL    };
  518.     static struct IntuiText AbsText = {
  519.         MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 10, 10, NULL,
  520.         (UBYTE *) "Select an absolute position", &RatioText    };
  521.     static struct IntuiText LRTBText[] = {
  522.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  523.             (UBYTE *) "Left", NULL    },
  524.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  525.             (UBYTE *) "Right", NULL    },
  526.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  527.             (UBYTE *) "Top", NULL    },
  528.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  529.             (UBYTE *) "Bottom", NULL    }
  530.     };
  531.     static struct StringInfo LRTBinfo[] = {
  532.         {    &Buffer[0][0], &Buffer[4][0], 0, 20, 0    },
  533.         {    &Buffer[1][0], &Buffer[4][0], 0, 20, 0    },
  534.         {    &Buffer[2][0], &Buffer[4][0], 0, 20, 0    },
  535.         {    &Buffer[3][0], &Buffer[4][0], 0, 20, 0    }
  536.     };
  537.     static struct Gadget LRTBGadget[] = {
  538.         {    &LRTBGadget[1], 66, 30, 160, 10,            /* next, LTWH */
  539.             GADGHCOMP,                                    /* Flags */
  540.             RELVERIFY,                                    /* Activation */
  541.             STRGADGET | REQGADGET,                        /* GadgetType */
  542.             (APTR) NULL, NULL,                            /* rendering */
  543.             &LRTBText[0], 0, (APTR) &LRTBinfo[0],        /* "Left" */
  544.             NEGGADGETID+1, NULL    },
  545.         {    &LRTBGadget[2], 66, 45, 160, 10,            /* next, LTWH */
  546.             GADGHCOMP,
  547.             RELVERIFY,
  548.             STRGADGET | REQGADGET,
  549.             (APTR) NULL, NULL,
  550.             &LRTBText[1], 0, (APTR) &LRTBinfo[1],        /* Right */
  551.             NEGGADGETID+1, NULL    },
  552.         {    &LRTBGadget[3], 66, 60, 160, 10,            /* next, LTWH */
  553.             GADGHCOMP,
  554.             RELVERIFY,
  555.             STRGADGET | REQGADGET,
  556.             (APTR) NULL, NULL,
  557.             &LRTBText[2], 0, (APTR) &LRTBinfo[2],        /* Top */
  558.             NEGGADGETID+1, NULL    },
  559.         {    NULL, 66, 75, 160, 10,                        /* next, LTWH */
  560.             GADGHCOMP,
  561.             RELVERIFY,
  562.             STRGADGET | REQGADGET,
  563.             (APTR) NULL, NULL,
  564.             &LRTBText[3], 0, (APTR) &LRTBinfo[3],        /* Bottom */
  565.             NEGGADGETID+1, NULL    }
  566.     };
  567.     static struct Requester AbsRequest = {
  568.         NULL, 25, 40, 260, 130, 0,0, &PositiveGadget, NULL,
  569.         &AbsText, 0, 1    };
  570.  
  571.     /* Stuff for the SHIFT requester */
  572.  
  573.     static struct IntuiText ShiftText = {
  574.         MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 10, 10, NULL,
  575.         (UBYTE *) "Select a window shift amount", NULL    };
  576.     static struct IntuiText RDText[] = {
  577.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  578.             (UBYTE *) "Right", NULL    },
  579.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -56, 0, NULL,
  580.             (UBYTE *) "Down", NULL    }
  581.     };
  582.     static struct Gadget RDGadget[] = {
  583.         {    &RDGadget[1], 66, 45, 160, 10,            /* next, LTWH */
  584.             GADGHCOMP,
  585.             0,
  586.             STRGADGET | REQGADGET,
  587.             (APTR) NULL, NULL,
  588.             &RDText[0], 0, (APTR) &LRTBinfo[0],        /* Right */
  589.             0, NULL    },
  590.         {    NULL, 66, 60, 160, 10,                    /* next, LTWH */
  591.             GADGHCOMP,
  592.             0,
  593.             STRGADGET | REQGADGET,
  594.             (APTR) NULL, NULL,
  595.             &RDText[1], 0, (APTR) &LRTBinfo[1],        /* Down */
  596.             0, NULL    }
  597.     };
  598.     static struct Requester ShiftRequest = {
  599.         NULL, 25, 40, 260, 130, 0,0, &PositiveGadget, NULL,
  600.         &ShiftText, 0, 1    };
  601.  
  602.     switch (SubNum) {
  603.     case PNRED: 
  604.         if (MouseStatus != FLASHING) return;
  605.         else {
  606.             register SHORT w = MainWindow -> GZZWidth,
  607.                            h = MainWindow -> GZZHeight;
  608.             register SHORT X1, Y1, X2, Y2;
  609.  
  610.             /* If you cast less, Aztec seems to do it wrong... */
  611.             X1 = (-(long)FrameX1 * w) / ((long)FrameX2 - (long)FrameX1);
  612.             Y1 = (-(long)FrameY1 * h) / ((long)FrameY2 - (long)FrameY1);
  613.             X2 = ((long)(w-1-FrameX1) * w) / ((long)FrameX2 - (long)FrameX1)
  614.                 - 1;
  615.             Y2 = ((long)(h-1-FrameY1) * h) / ((long)FrameY2 - (long)FrameY1)
  616.                 - 1;
  617. #ifdef DEBUG2
  618.             fprintf(stderr,"REDUCE: w=%d h=%d X1=%d Y1=%d X2=%d Y2=%d\n",
  619.                 w, h, X1, Y1, X2, Y2);
  620.             fprintf(stderr,"        FrameX1=%d FrameY1=%d FrameX2=%d FrameY2=%d\n",
  621.                 FrameX1, FrameY1, FrameX2, FrameY2);
  622. #endif
  623.  
  624.             NewLeftEdge   = LeftEdge + X1 * CXStep;
  625.             NewRightEdge  = LeftEdge + X2 * CXStep;
  626.             NewTopEdge    =  TopEdge - Y1 * CYStep;
  627.             NewBottomEdge =  TopEdge - Y2 * CYStep;
  628.  
  629.             skipto pnabs;
  630.         }
  631.     case PNENL:
  632.         if (MouseStatus != FLASHING) return;
  633.  
  634.         NewLeftEdge   = LeftEdge + FrameX1 * CXStep;
  635.         NewRightEdge  = LeftEdge + FrameX2 * CXStep;
  636.         NewTopEdge    =  TopEdge - FrameY1 * CYStep;
  637.         NewBottomEdge =  TopEdge - FrameY2 * CYStep;
  638.         skipto pnabs;
  639.     case PNSHF:
  640.         NegativeGadget.NextGadget = &RDGadget[0];
  641.         do {
  642.             sprintf(Buffer[0], "%1.6g",HShift);
  643.             sprintf(Buffer[1], "%1.6g",VShift);
  644.  
  645.             window = MyRequest(&ShiftRequest, MainWindow);
  646.             ID = WaitMyRequest(window);
  647.             EndMyRequest(&ShiftRequest, window, MainWindow);
  648.             if (ID == NEGGADGETID) return;
  649.  
  650.         } while (sscanf(Buffer[0], "%lf", &HShift)+
  651.                 sscanf(Buffer[1], "%lf", &VShift) != 2);
  652.  
  653.         NewLeftEdge   = LeftEdge + HShift * Width;
  654.         NewRightEdge  = RightEdge + HShift * Width;
  655.         NewTopEdge    = TopEdge + VShift * Height;
  656.         NewBottomEdge = BottomEdge + VShift * Height;
  657.  
  658.         skipto pnabs;
  659.     case PNABS:
  660.         NewLeftEdge = LeftEdge;
  661.         NewRightEdge = RightEdge;
  662.         NewTopEdge = TopEdge;
  663.         NewBottomEdge = BottomEdge;
  664.  
  665. pnabs:
  666.         NegativeGadget.NextGadget = &LRTBGadget[0];
  667.         sprintf(Buffer[0], "%1.10g", NewLeftEdge);
  668.         sprintf(Buffer[1], "%1.10g", NewRightEdge);
  669.         sprintf(Buffer[2], "%1.10g", NewTopEdge);
  670.         sprintf(Buffer[3], "%1.10g", NewBottomEdge);
  671.         sprintf(RatioText.IText+7, "%1.4f     ", Ratio(NewLeftEdge,
  672.                 NewRightEdge, NewTopEdge, NewBottomEdge, MainWindow));
  673.  
  674.         do {
  675.             window = MyRequest(&AbsRequest, MainWindow);
  676.  
  677.             while ( (ID = WaitMyRequest(window) ) > NEGGADGETID) {
  678.                 sscanf(Buffer[0], "%lf", &NewLeftEdge);
  679.                 sscanf(Buffer[1], "%lf", &NewRightEdge);
  680.                 sscanf(Buffer[2], "%lf", &NewTopEdge);
  681.                 sscanf(Buffer[3], "%lf", &NewBottomEdge);
  682.                 sprintf(RatioText.IText+7, "%1.4f     ",
  683.                     Ratio(NewLeftEdge, NewRightEdge, NewTopEdge,
  684.                     NewBottomEdge, MainWindow));
  685.  
  686.                 PrintIText(AbsRequest.ReqLayer->rp, &RatioText, 0L, 0L);
  687.             }
  688.  
  689.             EndMyRequest(&AbsRequest, window, MainWindow);
  690.  
  691.         } while (sscanf(Buffer[0], "%lf", &NewLeftEdge)+
  692.                  sscanf(Buffer[1], "%lf", &NewRightEdge)+
  693.                  sscanf(Buffer[2], "%lf", &NewTopEdge)+
  694.                  sscanf(Buffer[3], "%lf", &NewBottomEdge) < 4);
  695.  
  696.         if (ID != POSGADGETID) return;
  697.  
  698.         LeftEdge = NewLeftEdge;
  699.         RightEdge = NewRightEdge;
  700.         TopEdge = NewTopEdge;
  701.         BottomEdge = NewBottomEdge;
  702.  
  703.         StopFraming();
  704.         StopDrawing();
  705.         
  706.         break;
  707.     }
  708.     DrawPicture((bool)FALSE);    /* Don't fill in */
  709. }
  710.  
  711. float Ratio(l, r, t, b, window)
  712. double l, r, t, b;
  713. struct Window *window;
  714. {
  715.     float PixelRatio;
  716.     float ReImRatio;
  717.  
  718.     if (t == b) t = b+1;    /* You never know... */
  719.  
  720.     PixelRatio = (float) window->GZZWidth / window->GZZHeight;
  721.  
  722.     if (window->WScreen->ViewPort.Modes & HIRES) PixelRatio /= 2;
  723.     if (window->WScreen->ViewPort.Modes & LACE) PixelRatio *= 2;
  724.     ReImRatio = (r - l)/(t - b);
  725.  
  726.     return ReImRatio / PixelRatio;
  727. }
  728.  
  729. void Parameters()
  730. {
  731.     struct Window *window;
  732.     int ID;
  733.     int NewMaxDepth, NewRangeWidth;
  734.  
  735.     static struct IntuiText ParamText = {
  736.         MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 10, 10, NULL,
  737.         (UBYTE *) "Select these parameters", NULL    };
  738.     static struct IntuiText ParmText[] = {
  739.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -120, 0, NULL,
  740.             (UBYTE *) "Max depth", NULL    },
  741.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -120, 0, NULL,
  742.             (UBYTE *) "Range width", NULL    },
  743.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -120, 0, NULL,
  744.             (UBYTE *) "", NULL    },
  745.         {    MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, -120, 0, NULL,
  746.             (UBYTE *) "", NULL    }
  747.     };
  748.     static struct StringInfo Parminfo[] = {
  749.         {    &Buffer[0][0], &Buffer[4][0], 0, 20, 0    },
  750.         {    &Buffer[1][0], &Buffer[4][0], 0, 20, 0    },
  751.         {    &Buffer[2][0], &Buffer[4][0], 0, 20, 0    },
  752.         {    &Buffer[3][0], &Buffer[4][0], 0, 20, 0    }
  753.     };
  754.     static struct Gadget ParmGadget[] = {
  755.         {    &ParmGadget[1], 130, 30, 96, 10,            /* next, LTWH */
  756.             GADGHCOMP,                                    /* Flags */
  757.             RELVERIFY | LONGINT,                        /* Activation */
  758.             STRGADGET | REQGADGET,                        /* GadgetType */
  759.             (APTR) NULL, NULL,                            /* rendering */
  760.             &ParmText[0], 0, (APTR) &Parminfo[0],        /* "MaxDepth" */
  761.             0, NULL    },
  762.         {    &ParmGadget[2], 130, 45, 96, 10,            /* next, LTWH */
  763.             GADGHCOMP,
  764.             RELVERIFY | LONGINT,
  765.             STRGADGET | REQGADGET,
  766.             (APTR) NULL, NULL,
  767.             &ParmText[1], 0, (APTR) &Parminfo[1],        /* "RangeWidth" */
  768.             0, NULL    },
  769.         {    &ParmGadget[3], 130, 60, 96, 10,            /* next, LTWH */
  770.             GADGHCOMP,
  771.             RELVERIFY,
  772.             STRGADGET | REQGADGET,
  773.             (APTR) NULL, NULL,
  774.             &ParmText[2], 0, (APTR) &Parminfo[2],        /* */
  775.             0, NULL    },
  776.         {    NULL, 130, 75, 96, 10,                        /* next, LTWH */
  777.             GADGHCOMP,
  778.             RELVERIFY,
  779.             STRGADGET | REQGADGET,
  780.             (APTR) NULL, NULL,
  781.             &ParmText[3], 0, (APTR) &Parminfo[3],        /* */
  782.             0, NULL    }
  783.     };
  784.     static struct Requester ParmRequest = {
  785.         NULL, 25, 40, 260, 130, 0,0, &PositiveGadget, NULL,
  786.         &ParamText, 0, 1    };
  787.  
  788.     /* Stuff for the PARAMETERS requester */
  789.     NegativeGadget.NextGadget = &ParmGadget[0];
  790.     Parminfo[0].LongInt = MaxDepth;
  791.     Parminfo[1].LongInt = RangeWidth;
  792.     do {
  793.         sprintf(Buffer[0], "%ld", Parminfo[0].LongInt);
  794.         sprintf(Buffer[1], "%ld", Parminfo[1].LongInt);
  795.         Buffer[2][0] = Buffer[3][0] = '\0';
  796.  
  797.         window = MyRequest(&ParmRequest, MainWindow);
  798.         ID = WaitMyRequest(window);
  799.         EndMyRequest(&ParmRequest, window, MainWindow);
  800.         if (ID == NEGGADGETID) return;
  801.  
  802.         NewMaxDepth = Parminfo[0].LongInt;
  803.         NewRangeWidth = Parminfo[1].LongInt;
  804.     } while ( NewMaxDepth < 0 || NewMaxDepth > MAXDEPTH ||
  805.               NewRangeWidth < 0 || NewRangeWidth > MAXDEPTH );
  806.  
  807.     if (NewRangeWidth != RangeWidth)    InitPenTable();
  808.     MaxDepth = NewMaxDepth;
  809.     RangeWidth = NewRangeWidth;
  810. }
  811.